package cn.okcode.slowjson.parser;

import cn.okcode.slowjson.ast.*;
import cn.okcode.slowjson.internal.BeanUtils;
import cn.okcode.slowjson.internal.JsonException;
import cn.okcode.slowjson.internal.TypeUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 反序列化普通对象，即任意支持的对象
 *
 * @author pyk13
 */
public class JsonNodeReader {

    public Object read(AbstractNode<?> node, Type type) {
        if (node instanceof BoolNode) {
            return node.getValue();
        } else if (node instanceof NullNode) {
            return null;
        } else if (node instanceof NumberNode) {
            return node.getValue();
        } else if (node instanceof StringNode) {
            return node.getValue();
        } else if (node instanceof ObjectNode) {
            return read((ObjectNode) node, type);
        } else if (node instanceof ArrayNode) {
            return readArray((ArrayNode) node, type);
        } else {
            throw new JsonException("");
        }
    }

    public Object read(ObjectNode node, Type type) {
        Class<?> rawType = TypeUtils.getRawType(type);

        if (Map.class.isAssignableFrom(rawType)) {
            //Map对象
            return readMap(node, type);
        } else {
            //其它对象
            return readObject(node, type);
        }
    }

    public Object readArray(ArrayNode node, Type type) {

        if (!isArrayOrCollection(type)) {
            throw new JsonException("json数组只支持转换为数组或者Collection");
        }
        Type componentType = TypeUtils.getComponentType(type);
        if (componentType == null) {
            throw new JsonException("没有找到数组元素的类型，数组的类型：" + type.getTypeName());
        }

        @SuppressWarnings("unchecked")
        Collection<Object> collection = (Collection<Object>) TypeUtils.newInstance(Collection.class);

        for (AbstractNode<?> childNode : node.getElements()) {
            Object value = read(childNode, componentType);
            collection.add(value);
        }

        if (TypeUtils.isArray(type)) {
            Object arrayObject = TypeUtils.newArrayInstance(componentType, collection.size());

            BeanUtils.copyCollection(collection, arrayObject);

            return arrayObject;
        } else {
            return collection;
        }
    }

    public Object readObject(ObjectNode node, Type type) {
        Object object = TypeUtils.newInstance(type);
        Class<?> rawType = TypeUtils.getRawType(type);

        List<Field> fields = TypeUtils.getFields(rawType);

        for (Field field : fields) {
            String property = field.getName();
            AbstractNode<?> propNode = node.getPropertyValueNode(property);
            if (propNode == null) {
                //没有从json字符串中找到字段
                continue;
            }

            Object value = read(propNode, field.getGenericType());

            //设置获取到的值
            BeanUtils.setValue(object, field, value);
        }
        return object;
    }

    public Object readMap(ObjectNode node, Type type) {

        Class<?> rawType = TypeUtils.getRawType(type);
        if (!Map.class.isAssignableFrom(rawType)) {
            throw new JsonException("期望的类型是Map,实际是:" + type.getTypeName());
        }

        Type valueType = TypeUtils.getGenericTypeArgument(type, 1);

        //用来临时存放值的对象
        @SuppressWarnings("unchecked")
        Map<String, Object> object = (Map<String, Object>) TypeUtils.newInstance(type);

        for (Map.Entry<PropertyNode, AbstractNode<?>> entry : node.getProperties().entrySet()) {
            String key = entry.getKey().getValue();

            AbstractNode<?> propNode = entry.getValue();

            Object value = read(propNode, valueType);

            //设置获取到的值
            object.put(key, value);
        }

        return object;
    }

    public boolean isArrayOrCollection(Type type) {
        return TypeUtils.isCollection(type) || TypeUtils.isArray(type);
    }
}
